package com.photoeditor.demo.ui.widget.beauty;

import android.content.Context;
import android.content.res.Resources;
import android.content.res.TypedArray;
import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.DashPathEffect;
import android.graphics.Matrix;
import android.graphics.Paint;
import android.graphics.RectF;
import android.graphics.drawable.Drawable;
import android.net.Uri;
import android.support.v7.widget.AppCompatImageView;
import android.util.AttributeSet;
import android.view.GestureDetector;
import android.view.MotionEvent;
import android.view.View;
import android.view.ViewConfiguration;

import com.android.util.Stretch;
import com.common.base.ComponentContext;
import com.common.base.utils.DeviceUtils;
import com.photoeditor.R;
import com.photoeditor.demo.model.image.collage.util.MathUtil;
import com.photoeditor.demo.ui.widget.image.attacher.CanvasPhotoViewAttacher;
import com.photoeditor.demo.ui.widget.image.attacher.IPhotoView;
import com.photoeditor.demo.util.AsyncTask;

/**
 * 丰胸的View
 */
public class BreastView extends AppCompatImageView implements IPhotoView {

    public static final int TYPE_BREAST = 1;//丰胸
    public static final int TYPE_BUTTOCKS = 2;//丰臀

    private static final float TouchSlop = ViewConfiguration.get(ComponentContext.getContext()).getScaledTouchSlop();
    public static final float DEFAULT_RADIUS = DeviceUtils.dip2px(36);
    public final static float BUTTON_WIDTH = DeviceUtils.dip2px(16);
    public final static float BUTTON_TOUCH_WIDTH = DeviceUtils.dip2px(14);//扩大触摸区域
    public final static float c = (float) Math.sqrt(2) / 2;
    public final static int SMALLEST_SIZE = DeviceUtils.dip2px(50);
    public final static float MAX_SIZE = DeviceUtils.dip2px(320);
    public final static float BUTTOCKS_WIDTH = DeviceUtils.dip2px(34);
    public final static float BUTTOCKS_HEIGHT = DeviceUtils.dip2px(70);
    public final static float BREAST_STRENGTH_MIN = 0.0005F;
    public final static float BREAST_STRENGTH_MAX = 0.8f;
    public final static float BUTTOCKS_STRENGTH_MAX = DeviceUtils.dip2px(20);

    private int mType = TYPE_BREAST;

    private Bitmap mOriginalBitmap;
    //原来的Bitmap
    private Bitmap mSrcBitmap;

    private Bitmap mStretchBitmap;

    //用于标识是否初始化
    private boolean mIsInit = false;

    //本界面的Bound Rect
    private RectF mRect;

    //Drawable的Bound Rect  默认
    private RectF mDrawableRect;

    private final CanvasPhotoViewAttacher mAttacher;

    /**
     * 这个是图片的Bounds Drawable
     */
    private RectF mBaseDrawableRect;

    private int mMode = MODE_NONE;
    public static final int MODE_NONE = 0;
    public static final int MODE_MOVE_LEFT = 1;
    public static final int MODE_MOVE_RIGHT = 2;
    public static final int MODE_SCALE_OR_ROTATION_OR_MOVE_LEFT = 3;
    public static final int MODE_SCALE_OR_ROTATION_OR_MOVE_RIGHT = 4;
    public static final int MODE_SCALE_OR_ROTATION_LEFT = 5;
    public static final int MODE_SCALE_OR_ROTATION_RIGHT = 6;
    public static final int MODE_CLICK_BUTTON = 7;

    private float mDownX;
    private float mDownY;

    private int mStrength;

    private CanvasPhotoViewAttacher.OnMatrixChangedListener mMatrixChangeListener = new CanvasPhotoViewAttacher.OnMatrixChangedListener() {
        @Override
        public void onMatrixChanged(RectF rect) {
            if (mDrawableRect == null) {
                mDrawableRect = new RectF();
            }
            mDrawableRect.set(rect);
            if (mIsInit) {
                countScaleAndDo();
            }
            invalidate();
        }
    };
    private Paint mCirclePaint;

    private CircleRect mCircleRectLeft;
    private CircleRect mCircleRectRight;
    private boolean mClickDeleteLeft;
    private boolean mClickDeleteRight;
    private RectF mSupportDrawableRect;
    private Matrix mCacheMatrix;
    private Stretch mStretch;
    private int mBitmapW;
    private int mBitmapH;
    private float mScaleWidth;
    private float mScaleHeight;
    private AsyncTask<Object, Void, Bitmap> mGetBitmapTask;
    private boolean mDrawOther;

    public BreastView(Context context) {
        this(context, null, 0);
    }

    public BreastView(Context context, AttributeSet attrs) {
        this(context, attrs, 0);
    }

    public BreastView(Context context, AttributeSet attrs,
                      int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        super.setScaleType(ScaleType.MATRIX);
        if (attrs != null) {
            TypedArray ta = context.obtainStyledAttributes(attrs, R.styleable.BreastView);
            mType = ta.getInteger(R.styleable.BreastView_type, TYPE_BREAST);
        }
        mAttacher = new CanvasPhotoViewAttacher(this);
        setOnMatrixChangeListener(mMatrixChangeListener);
        initialize();
    }


    private void initialize() {
        setWillNotDraw(false);
        setLayerType(View.LAYER_TYPE_SOFTWARE, null);
        setMaximumScale(8.0f);
        setMediumScale(1.0f);

        mCirclePaint = new Paint(Paint.ANTI_ALIAS_FLAG);
        mCirclePaint.setStyle(Paint.Style.STROKE);
        mCirclePaint.setColor(Color.WHITE);
        int width = DeviceUtils.dip2px(2);
        mCirclePaint.setStrokeWidth(width);
        float dp1 = DeviceUtils.dip2px(ComponentContext.getContext(), 8);
        float dp2 = DeviceUtils.dip2px(ComponentContext.getContext(), 4);
        DashPathEffect dashPathEffect = new DashPathEffect(new float[]{dp1, dp2}, 0);
        mCirclePaint.setPathEffect(dashPathEffect);

        mCirclePaint.setShadowLayer(width, width / 2, width / 2, 0xff474747);

        mCacheMatrix = new Matrix();

        mStretch = new Stretch();

        resetStrength();
        mDrawOther = true;
    }

    public void setProgress(int progress) {
        if (progress != mStrength) {
            if (mType == TYPE_BREAST) {
                doBreast(progress);
            } else {
                doButtocks(progress);
            }
        }
    }

    private void doBreast(int progress) {
        if (progress == 0) {
            mSrcBitmap = mStretchBitmap;
            setImageBitmap(mSrcBitmap);
            mStrength = 0;
            return;
        }
        mSrcBitmap = mStretchBitmap.copy(Bitmap.Config.ARGB_8888, true);
        mStretch.createWarp(mSrcBitmap, mSrcBitmap.getWidth(), mSrcBitmap.getHeight());
        final float strength = BREAST_STRENGTH_MIN + (BREAST_STRENGTH_MAX - BREAST_STRENGTH_MIN) * progress / 100.0f;
        new AsyncTask<Object, Void, Bitmap>() {

            @Override
            protected void onPreExecute() {
                super.onPreExecute();
                if (mBreastViewListener != null) {
                    mBreastViewListener.showLoading();
                }
            }

            @Override
            protected Bitmap doInBackground(Object... objects) {
                int radius, x, y;
                int[] ints = new int[]{};
                RectF displayRect = mAttacher.getDisplayRect();
                float scale = mAttacher.getScale();
                if (mCircleRectLeft.isShow()) {
                    radius = (int) (mCircleRectLeft.mRadius * mScaleWidth / scale / 2);
                    x = (int) ((mCircleRectLeft.mCenterX - displayRect.left) * mScaleWidth / scale);
                    y = (int) ((mCircleRectLeft.mCenterY - displayRect.top) * mScaleHeight / scale);
                    mStretch.beginWarp(Stretch.WARPER_GROW, radius, x, y);
                    mStretch.setStrength(strength);
                    mStretch.updateWarp(x, y);

                    ints = mStretch.endWarp(x, y);
                }

                if (mCircleRectRight.isShow()) {
                    radius = (int) (mCircleRectRight.mRadius * mScaleWidth / scale / 2);
                    x = (int) ((mCircleRectRight.mCenterX - displayRect.left) * mScaleWidth / scale);
                    y = (int) ((mCircleRectRight.mCenterY - displayRect.top) * mScaleHeight / scale);
                    mStretch.beginWarp(Stretch.WARPER_GROW, radius, x, y);
                    mStretch.setStrength(strength);
                    mStretch.updateWarp(x, y);

                    ints = mStretch.endWarp(x, y);
                }
                mStretch.releaseWarp();
                if (mSrcBitmap != null && !mSrcBitmap.isRecycled()) {
                    mSrcBitmap.setPixels(ints, 0, mBitmapW, 0, 0, mBitmapW, mBitmapH);
                }
                return mSrcBitmap;
            }

            @Override
            protected void onPostExecute(Bitmap bitmap) {
                super.onPostExecute(bitmap);
                if (mBreastViewListener != null) {
                    mBreastViewListener.hideLoading();
                }
                if (bitmap != null && !bitmap.isRecycled()) {
                    setImageBitmap(bitmap);
                }
            }
        }.executeOnExecutor(AsyncTask.DUAL_THREAD_EXECUTOR);
        mStrength = progress;
    }

    private void doButtocks(int s) {
        if (s == 50) {
            mSrcBitmap = mStretchBitmap;
            setImageBitmap(mSrcBitmap);
            mStrength = 50;
            return;
        }
        mSrcBitmap = mStretchBitmap.copy(Bitmap.Config.ARGB_8888, true);
        mStretch.createWarp(mSrcBitmap, mSrcBitmap.getWidth(), mSrcBitmap.getHeight());
        new AsyncTask<Object, Void, Bitmap>() {

            @Override
            protected void onPreExecute() {
                super.onPreExecute();
                if (mBreastViewListener != null) {
                    mBreastViewListener.showLoading();
                }
            }

            @Override
            protected Bitmap doInBackground(Object... objects) {
                int progress = (int) objects[0];
                int radius, x, y;
                int[] ints = new int[]{};
                float strength = BUTTOCKS_STRENGTH_MAX * Math.abs(progress) / 50.0f;
                float degree;
                RectF displayRect = mAttacher.getDisplayRect();
                float scale = mAttacher.getScale();
                if (mCircleRectLeft.isShow()) {
                    radius = (int) (mCircleRectLeft.mRadius * mScaleWidth / scale / 2);
                    x = (int) ((mCircleRectLeft.mCenterX - displayRect.left) * mScaleWidth / scale);
                    y = (int) ((mCircleRectLeft.mCenterY - displayRect.top) * mScaleHeight / scale);
                    mStretch.beginWarp(Stretch.WARPER_TRANSLATE, radius, x, y);

                    degree = (float) (mCircleRectLeft.getDegree() * Math.PI / 180.0f);
                    if (progress > 0) {
                        //放大
                        x = x - (int) (strength * Math.cos(degree));
                        y = y - (int) (strength * Math.sin(degree));
                    } else {
                        //缩小
                        x = x + (int) (strength * Math.cos(degree));
                        y = y + (int) (strength * Math.sin(degree));
                    }
                    mStretch.updateWarp(x, y);

                    ints = mStretch.endWarp(x, y);
                }

                if (mCircleRectRight.isShow()) {
                    radius = (int) (mCircleRectRight.mRadius * mScaleWidth / scale / 2);
                    x = (int) ((mCircleRectRight.mCenterX - displayRect.left) * mScaleWidth / scale);
                    y = (int) ((mCircleRectRight.mCenterY - displayRect.top) * mScaleHeight / scale);
                    mStretch.beginWarp(Stretch.WARPER_TRANSLATE, radius, x, y);

                    degree = (float) (mCircleRectLeft.getDegree() * Math.PI / 180.0f);
                    if (progress > 0) {
                        //放大
                        x = x + (int) (strength * Math.cos(degree));
                        y = y + (int) (strength * Math.sin(degree));
                    } else {
                        //缩小
                        x = x - (int) (strength * Math.cos(degree));
                        y = y - (int) (strength * Math.sin(degree));
                    }
                    mStretch.updateWarp(x, y);

                    ints = mStretch.endWarp(x, y);
                }
                mStretch.releaseWarp();
                mSrcBitmap.setPixels(ints, 0, mBitmapW, 0, 0, mBitmapW, mBitmapH);
                return mSrcBitmap;
            }

            @Override
            protected void onPostExecute(Bitmap bitmap) {
                super.onPostExecute(bitmap);
                if (mBreastViewListener != null) {
                    mBreastViewListener.hideLoading();
                }
                setImageBitmap(bitmap);
            }
        }.executeOnExecutor(AsyncTask.DUAL_THREAD_EXECUTOR, s - 50);
        mStrength = s;
    }

    private BreastViewListener mBreastViewListener;

    public void setBreastViewListener(BreastViewListener breastViewListener) {
        mBreastViewListener = breastViewListener;
    }

    public interface BreastViewListener {
        void showLoading();

        void hideLoading();

        void resetSeekBar();
    }

    /**
     * 设置原图
     */
    public void setOriginalBitmap(Bitmap bm) {
        mOriginalBitmap = bm;
        mStretchBitmap = bm;
    }

    /**
     * @param bm
     * @param updateMatrix 是否重置当前的Matrix
     */
    public void setImageBitmap(Bitmap bm, boolean updateMatrix) {
        super.setImageBitmap(bm);
        if (mSrcBitmap == null || bm == null || (mSrcBitmap != bm && (mSrcBitmap.getWidth() != bm.getWidth() || mSrcBitmap.getHeight() != bm.getHeight()))) {
            mIsInit = false;
        }
        if (bm != null) {
            mSrcBitmap = bm.copy(bm.getConfig(), true);
        } else {
            mSrcBitmap = bm;
        }
        if (updateMatrix && null != mAttacher) {
            mAttacher.update();
        }
    }

    @Override
    public void setImageBitmap(Bitmap bm) {
        setImageBitmap(bm, false);
    }

    @Override
    protected void onLayout(boolean changed, int left, int top, int right,
                            int bottom) {
        super.onLayout(changed, left, top, right, bottom);
        mRect = new RectF(0, 0, right - left, bottom - top);
        if (!mIsInit && mSrcBitmap != null && !mSrcBitmap.isRecycled()) {
            init();
        }
    }

    public void init() {
        if (!mIsInit) {
            countDrawableInitPosition(mRect);
            mBaseDrawableRect = new RectF(0, 0, getDrawable().getIntrinsicWidth(), getDrawable().getIntrinsicHeight());

            mBitmapW = (int) mBaseDrawableRect.width();
            mBitmapH = (int) mBaseDrawableRect.height();
            mScaleWidth = mBaseDrawableRect.width() / mSupportDrawableRect.width();
            mScaleHeight = mBaseDrawableRect.height() / mSupportDrawableRect.height();

            addCircleBean();

            mIsInit = true;
            invalidate();
        }
    }

    private void addCircleBean() {
        if (mType == TYPE_BREAST) {
            float x = DeviceUtils.dip2px(44);
            mCircleRectLeft = new CircleRect(mRect.centerX() - x, mRect.centerY(), DEFAULT_RADIUS, 1);
            mCircleRectRight = new CircleRect(mRect.centerX() + x, mRect.centerY(), DEFAULT_RADIUS, 2);
        } else {
            float x = DeviceUtils.dip2px(42);
            mCircleRectLeft = new CircleRect(mRect.centerX() - x, mRect.centerY(), 1);
            mCircleRectRight = new CircleRect(mRect.centerX() + x, mRect.centerY(), 2);
        }
    }

    private void countDrawableInitPosition(RectF viewRect) {
        mSupportDrawableRect = new RectF();
        float width = mSrcBitmap.getWidth();
        float height = mSrcBitmap.getHeight();

        float vW = viewRect.width();
        float vH = viewRect.height();

        float w, h;

        if (width / height > vW / vH) {//宽顶着
            w = vW;
            h = w / width * height;
        } else {//高顶着
            h = vH;
            w = h / height * width;
        }

        mSupportDrawableRect.left = (vW - w) / 2 + viewRect.left;
        mSupportDrawableRect.top = (vH - h) / 2 + viewRect.top;
        mSupportDrawableRect.right = mSupportDrawableRect.left + w;
        mSupportDrawableRect.bottom = mSupportDrawableRect.top + h;
    }

    /**
     * 先绘制未选中的  然后绘制选中的
     */
    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        if (!mIsInit || mSrcBitmap == null || mSrcBitmap.isRecycled()) {
            return;
        }

        canvas.clipRect(mDrawableRect);//裁剪到当前显示区域内

        if (mDrawOther) {
            mCircleRectRight.onDraw(canvas);
            mCircleRectLeft.onDraw(canvas);
        }

    }

    boolean mClick;
    float oldDist = 1f;
    float oldRotation = 0;
    boolean clickSpace;

    @Override
    public boolean onTouchEvent(MotionEvent event) {
        if (!mIsInit || mSrcBitmap == null || mSrcBitmap.isRecycled()) {
            return super.onTouchEvent(event);
        }
        switch (event.getAction() & MotionEvent.ACTION_MASK) {
            case MotionEvent.ACTION_DOWN:
                if (event.getPointerCount() != 1) {
                    break;
                }
                mDownX = event.getX();
                mDownY = event.getY();
                mClick = true;
                clickSpace = false;

                float[] dst = new float[2];
                boolean show = mCircleRectLeft.isShow();
                if (mDrawOther && show) {
                    mCircleRectLeft.getRotateMatrix().mapPoints(dst, new float[]{mDownX, mDownY});
                    if (mCircleRectLeft.getDeleteRect().contains(dst[0], dst[1])) {
                        mClickDeleteLeft = true;
                        mMode = MODE_CLICK_BUTTON;
                        return true;
                    } else if (mCircleRectLeft.getScaleRect().contains(dst[0], dst[1])) {
                        mMode = MODE_SCALE_OR_ROTATION_LEFT;
                        return true;
                    } else if (mCircleRectLeft.getRectF().contains(dst[0], dst[1])) {
                        mMode = MODE_MOVE_LEFT;
                        return true;
                    }
                }
                show = mCircleRectRight.isShow();
                if (mDrawOther && show) {
                    dst = new float[2];
                    mCircleRectRight.getRotateMatrix().mapPoints(dst, new float[]{mDownX, mDownY});
                    if (mCircleRectRight.getDeleteRect().contains(dst[0], dst[1])) {
                        mClickDeleteRight = true;
                        mMode = MODE_CLICK_BUTTON;
                        return true;
                    } else if (mCircleRectRight.getScaleRect().contains(dst[0], dst[1])) {
                        mMode = MODE_SCALE_OR_ROTATION_RIGHT;
                        return true;
                    } else if (mCircleRectRight.getRectF().contains(dst[0], dst[1])) {
                        mMode = MODE_MOVE_RIGHT;
                        return true;
                    }
                }
                if (mDrawOther) {
                    clickSpace = true;
                }
                mDrawOther = true;
                mMode = MODE_NONE;
                mAttacher.onTouch(this, event);
                return true;
            case MotionEvent.ACTION_POINTER_DOWN:
                oldDist = spacing(event);
                oldRotation = rotation(event);
                float[] dst1 = new float[2];
                mClick = true;
                clickSpace = false;
                mDrawOther = true;
                if (mDrawOther && mCircleRectLeft.isShow()) {
                    mCircleRectLeft.getRotateMatrix().mapPoints(dst1, new float[]{event.getX(0), event.getY(0)});
                    if (mCircleRectLeft.getRectF().contains(dst1[0], dst1[1])) {
                        mMode = MODE_SCALE_OR_ROTATION_OR_MOVE_LEFT;
                        return true;
                    }
                }
                if (mDrawOther && mCircleRectRight.isShow()) {
                    dst1 = new float[2];
                    mCircleRectRight.getRotateMatrix().mapPoints(dst1, new float[]{event.getX(0), event.getY(0)});
                    if (mCircleRectRight.getRectF().contains(dst1[0], dst1[1])) {
                        mMode = MODE_SCALE_OR_ROTATION_OR_MOVE_RIGHT;
                        return true;
                    }
                }
                mMode = MODE_NONE;
                mAttacher.onTouch(this, event);
                return true;
            case MotionEvent.ACTION_MOVE:
                if (mMode == MODE_NONE) {
                    mAttacher.onTouch(this, event);
                }
                if (event.getPointerCount() > 1
                        && (mMode == MODE_SCALE_OR_ROTATION_OR_MOVE_RIGHT || mMode == MODE_SCALE_OR_ROTATION_OR_MOVE_LEFT)) {
                    float newDist = spacing(event);
                    if (mClick && Math.abs(newDist - oldDist) <= TouchSlop) {
                        return super.onTouchEvent(event);
                    }
                    mClick = false;
                    clickSpace = false;
                    mClickDeleteLeft = false;
                    mClickDeleteRight = false;
                    float rotation = rotation(event) - oldRotation;
                    float scale = newDist / oldDist;
                    if (mMode == MODE_SCALE_OR_ROTATION_OR_MOVE_LEFT) {
                        mCircleRectLeft.setDegree(rotation);
                        mCircleRectLeft.setScale(scale);
                        refresh();
                    } else if (mMode == MODE_SCALE_OR_ROTATION_OR_MOVE_RIGHT) {
                        mCircleRectRight.setDegree(rotation);
                        mCircleRectRight.setScale(scale);
                        refresh();
                    }
                    oldRotation = rotation(event);
                    oldDist = newDist;
                    return true;
                } else {
                    float nowX = event.getX();
                    float nowY = event.getY();
                    float dx = nowX - mDownX;
                    float dy = nowY - mDownY;
                    if (mClick && Math.abs(dx) <= TouchSlop
                            && Math.abs(dy) <= TouchSlop) {
                        return super.onTouchEvent(event);
                    }
                    mClick = false;
                    clickSpace = false;
                    mClickDeleteLeft = false;
                    mClickDeleteRight = false;
                    if (mMode == MODE_MOVE_LEFT) {
                        mCircleRectLeft.move(dx, dy);
                        refresh();
                    } else if (mMode == MODE_SCALE_OR_ROTATION_LEFT) {
                        mCircleRectLeft.dealScaleAndRotation(mDownX, mDownY, nowX, nowY);
                        refresh();
                    } else if (mMode == MODE_MOVE_RIGHT) {
                        mCircleRectRight.move(dx, dy);
                        refresh();
                    } else if (mMode == MODE_SCALE_OR_ROTATION_RIGHT) {
                        mCircleRectRight.dealScaleAndRotation(mDownX, mDownY, nowX, nowY);
                        refresh();
                    }
                    mDownX = nowX;
                    mDownY = nowY;
                }
                break;
            case MotionEvent.ACTION_CANCEL:
            case MotionEvent.ACTION_UP:
            case MotionEvent.ACTION_POINTER_UP:
                if (mMode == MODE_NONE) {
                    mAttacher.onTouch(this, event);
                }
                if (mClickDeleteLeft) {
                    if (mCircleRectLeft.isDrawAddIcon()) {
                        mCircleRectRight.setShow(true);
                        mCircleRectLeft.setDrawAddIcon(false);
                    } else {
                        mCircleRectLeft.setShow(false);
                        mCircleRectRight.setDrawAddIcon(true);
                    }
                    mClickDeleteLeft = false;
                } else if (mClickDeleteRight) {
                    if (mCircleRectRight.isDrawAddIcon()) {
                        mCircleRectLeft.setShow(true);
                        mCircleRectRight.setDrawAddIcon(false);
                    } else {
                        mCircleRectRight.setShow(false);
                        mCircleRectLeft.setDrawAddIcon(true);
                    }
                    mClickDeleteRight = false;
                }

                if (mMode == MODE_MOVE_RIGHT || mMode == MODE_MOVE_LEFT
                        || mMode == MODE_SCALE_OR_ROTATION_LEFT || mMode == MODE_SCALE_OR_ROTATION_RIGHT) {
                    mStretchBitmap = mSrcBitmap;
                    resetStrength();
                    if (mBreastViewListener != null) {
                        mBreastViewListener.resetSeekBar();
                    }
                }
                if (clickSpace && mDrawOther) {
                    mDrawOther = false;
                }

                mClick = false;
                refresh();
                break;
        }
        return super.onTouchEvent(event);
    }

    private void refresh() {
        invalidate();
    }

    private float spacing(MotionEvent event) {
        float x = event.getX(0) - event.getX(1);
        float y = event.getY(0) - event.getY(1);
        return (float) Math.sqrt(x * x + y * y);
    }

    private float rotation(MotionEvent event) {
        double delta_x = (event.getX(0) - event.getX(1));
        double delta_y = (event.getY(0) - event.getY(1));
        double radians = Math.atan2(delta_y, delta_x);
        return (float) Math.toDegrees(radians);
    }

    public void showOriginalBitmap() {
        super.setImageBitmap(mOriginalBitmap);
    }

    public void showEffect() {
        setImageBitmap(mSrcBitmap, false);
    }

    public Bitmap getCurBitmap() {
        if (mSrcBitmap != null) {
            return mSrcBitmap;
        }
        return mOriginalBitmap;
    }

    /**
     * 清除所有的
     */
    public void reset() {
        mOriginalBitmap = null;
        setImageBitmap(null);
        resetStrength();
        if (mType == TYPE_BREAST) {
            float x = DeviceUtils.dip2px(44);
            mCircleRectLeft.reset(mRect.centerX() - x, mRect.centerY(), DEFAULT_RADIUS);
            mCircleRectRight.reset(mRect.centerX() + x, mRect.centerY(), DEFAULT_RADIUS);
        } else {
            float x = DeviceUtils.dip2px(42);
            mCircleRectLeft.reset(mRect.centerX() - x, mRect.centerY());
            mCircleRectRight.reset(mRect.centerX() + x, mRect.centerY());
        }
        mDrawOther = true;
    }

    private void resetStrength() {
        if (mType == TYPE_BREAST) {
            mStrength = 0;
        } else {
            mStrength = 50;
        }
    }

    ///########################################

    @Override
    public void setPhotoViewRotation(float rotationDegree) {
        mAttacher.setRotationTo(rotationDegree);
    }

    @Override
    public void setRotationTo(float rotationDegree) {
        mAttacher.setRotationTo(rotationDegree);
    }

    @Override
    public void setRotationBy(float rotationDegree) {
        mAttacher.setRotationBy(rotationDegree);
    }

    @Override
    public boolean canZoom() {
        return mAttacher.canZoom();
    }

    @Override
    public RectF getDisplayRect() {
        return mAttacher.getDisplayRect();
    }

    @Override
    public Matrix getDisplayMatrix() {
        return mAttacher.getDrawMatrix();
    }

    @Override
    public boolean setDisplayMatrix(Matrix finalRectangle) {
        return mAttacher.setDisplayMatrix(finalRectangle);
    }

    @Override
    @Deprecated
    public float getMinScale() {
        return getMinimumScale();
    }

    @Override
    public float getMinimumScale() {
        return mAttacher.getMinimumScale();
    }

    @Override
    @Deprecated
    public float getMidScale() {
        return getMediumScale();
    }

    @Override
    public float getMediumScale() {
        return mAttacher.getMediumScale();
    }

    @Override
    @Deprecated
    public float getMaxScale() {
        return getMaximumScale();
    }

    @Override
    public float getMaximumScale() {
        return mAttacher.getMaximumScale();
    }

    @Override
    public float getScale() {
        return mAttacher.getScale();
    }

    @Override
    public ScaleType getScaleType() {
        return mAttacher.getScaleType();
    }

    @Override
    public void setAllowParentInterceptOnEdge(boolean allow) {
        mAttacher.setAllowParentInterceptOnEdge(allow);
    }

    @Override
    @Deprecated
    public void setMinScale(float minScale) {
        setMinimumScale(minScale);
    }

    @Override
    public void setMinimumScale(float minimumScale) {
        mAttacher.setMinimumScale(minimumScale);
    }

    @Override
    @Deprecated
    public void setMidScale(float midScale) {
        setMediumScale(midScale);
    }

    @Override
    public void setMediumScale(float mediumScale) {
        mAttacher.setMediumScale(mediumScale);
    }

    @Override
    @Deprecated
    public void setMaxScale(float maxScale) {
        setMaximumScale(maxScale);
    }

    @Override
    public void setMaximumScale(float maximumScale) {
        mAttacher.setMaximumScale(maximumScale);
    }


    @Override
    public void setImageResource(int resId) {
        super.setImageResource(resId);
        if (null != mAttacher) {
            mAttacher.update();
        }
    }

    @Override
    public void setImageURI(Uri uri) {
        super.setImageURI(uri);
        if (null != mAttacher) {
            mAttacher.update();
        }
    }

    @Override
    public void setOnMatrixChangeListener(CanvasPhotoViewAttacher.OnMatrixChangedListener listener) {
        mAttacher.setOnMatrixChangeListener(listener);
    }

    @Override
    public void setOnLongClickListener(OnLongClickListener l) {
        mAttacher.setOnLongClickListener(l);
    }

    @Override
    public void setOnPhotoTapListener(CanvasPhotoViewAttacher.OnPhotoTapListener listener) {
        mAttacher.setOnPhotoTapListener(listener);
    }

    @Override
    public CanvasPhotoViewAttacher.OnPhotoTapListener getOnPhotoTapListener() {
        return mAttacher.getOnPhotoTapListener();
    }

    @Override
    public void setOnViewTapListener(CanvasPhotoViewAttacher.OnViewTapListener listener) {
        mAttacher.setOnViewTapListener(listener);
    }

    @Override
    public CanvasPhotoViewAttacher.OnViewTapListener getOnViewTapListener() {
        return mAttacher.getOnViewTapListener();
    }

    @Override
    public void setScale(float scale) {
        mAttacher.setScale(scale);
    }

    @Override
    public void setScale(float scale, boolean animate) {
        mAttacher.setScale(scale, animate);
    }

    @Override
    public void setScale(float scale, float focalX, float focalY, boolean animate) {
        mAttacher.setScale(scale, focalX, focalY, animate);
    }

    @Override
    public void setScaleType(ScaleType scaleType) {
        if (null != mAttacher) {
            mAttacher.setScaleType(scaleType);
        }
    }

    @Override
    public void setZoomable(boolean zoomable) {
        mAttacher.setZoomable(zoomable);
    }

    @Override
    public Bitmap getVisibleRectangleBitmap() {
        return mAttacher.getVisibleRectangleBitmap();
    }

    @Override
    public void setZoomTransitionDuration(int milliseconds) {
        mAttacher.setZoomTransitionDuration(milliseconds);
    }

    @Override
    public IPhotoView getIPhotoViewImplementation() {
        return mAttacher;
    }

    @Override
    public void setOnDoubleTapListener(GestureDetector.OnDoubleTapListener newOnDoubleTapListener) {
        mAttacher.setOnDoubleTapListener(newOnDoubleTapListener);
    }

    @Override
    public float getBaseScale() {
        return mAttacher.getBaseScale();
    }

    @Override
    protected void onDetachedFromWindow() {
        mAttacher.cleanup();
        super.onDetachedFromWindow();
    }

    private void countScaleAndDo() {
        if (mCircleRectLeft != null) {
            mCircleRectLeft.doScaleMove(mBaseDrawableRect, mSupportDrawableRect, getImageMatrix(), mCacheMatrix, mRect);
        }
        if (mCircleRectRight != null) {
            mCircleRectRight.doScaleMove(mBaseDrawableRect, mSupportDrawableRect, getImageMatrix(), mCacheMatrix, mRect);
        }
    }

    private class CircleRect {
        //中心
        private float mCenterX;
        private float mCenterY;
        //半径
        private float mRadius;
        //圆矩形
        private RectF mRectF;

        private RectF mDeleteRect;
        private RectF mScaleRect;
        private RectF mButtonRect;

        private Drawable mDrawableDelete;
        private Drawable mDrawableScale;
        private Drawable mDrawableAdd;
        private Drawable mDrawableContent;
        private boolean mDrawAddIcon;
        private Matrix mMatrix;
        private float mDegree;
        private boolean mShow;
        private int mPosType;//1 left 2 right

        public CircleRect(float centerX, float centerY, float radius, int posType) {
            mCenterX = centerX;
            mCenterY = centerY;
            mRadius = radius;
            mPosType = posType;
            mRectF = new RectF(mCenterX - mRadius, mCenterY - mRadius, mCenterX + mRadius, mCenterY + mRadius);

            Resources resources = ComponentContext.getContext().getResources();
            mDrawableDelete = resources.getDrawable(R.drawable.ic_close_emoji);
            if (mPosType == 1) {
                mDrawableScale = resources.getDrawable(R.drawable.ic_boom_zoom_left);
            } else {
                mDrawableScale = resources.getDrawable(R.drawable.ic_boom_zoom_right);
            }
            mDrawableAdd = resources.getDrawable(R.drawable.ic_boom_add);

            mDrawAddIcon = false;
            mShow = true;
            mDegree = 0;
            mMatrix = new Matrix();

            mDeleteRect = new RectF();
            mScaleRect = new RectF();
            mButtonRect = new RectF();
            updateOtherRect();
        }

        public CircleRect(float centerX, float centerY, int posType) {
            mCenterX = centerX;
            mCenterY = centerY;
            mPosType = posType;
            mRadius = BUTTOCKS_HEIGHT;
            mRectF = new RectF(mCenterX - BUTTOCKS_WIDTH, mCenterY - BUTTOCKS_HEIGHT, mCenterX + BUTTOCKS_WIDTH, mCenterY + BUTTOCKS_HEIGHT);

            Resources resources = ComponentContext.getContext().getResources();
            mDrawableDelete = resources.getDrawable(R.drawable.ic_close_emoji);
            if (mPosType == 1) {
                mDrawableScale = resources.getDrawable(R.drawable.ic_boom_zoom_left);
                mDrawableContent = resources.getDrawable(R.drawable.ic_boom_scope_left);
            } else {
                mDrawableScale = resources.getDrawable(R.drawable.ic_boom_zoom_right);
                mDrawableContent = resources.getDrawable(R.drawable.ic_boom_scope_right);
            }
            mDrawableAdd = resources.getDrawable(R.drawable.ic_boom_add);

            mDrawAddIcon = false;
            mShow = true;
            mDegree = 0;
            mMatrix = new Matrix();

            mDeleteRect = new RectF();
            mScaleRect = new RectF();
            mButtonRect = new RectF();
            updateOtherRect();
        }

        private void updateOtherRect() {
            if (mType == TYPE_BREAST) {
                if (mPosType == 1) {
                    float x = mRadius * c;
                    float centerX = mCenterX - x;
                    float centerY = mCenterY - x;
                    mDeleteRect.set(centerX - BUTTON_WIDTH, centerY - BUTTON_WIDTH, centerX + BUTTON_WIDTH, centerY + BUTTON_WIDTH);

                    centerX = mCenterX - x;
                    centerY = mCenterY + x;
                    mScaleRect.set(centerX - BUTTON_WIDTH, centerY - BUTTON_WIDTH, centerX + BUTTON_WIDTH, centerY + BUTTON_WIDTH);

                } else if (mPosType == 2) {
                    float x = mRadius * c;
                    float centerX = mCenterX + x;
                    float centerY = mCenterY - x;
                    mDeleteRect.set(centerX - BUTTON_WIDTH, centerY - BUTTON_WIDTH, centerX + BUTTON_WIDTH, centerY + BUTTON_WIDTH);

                    centerX = mCenterX + x;
                    centerY = mCenterY + x;
                    mScaleRect.set(centerX - BUTTON_WIDTH, centerY - BUTTON_WIDTH, centerX + BUTTON_WIDTH, centerY + BUTTON_WIDTH);

                }
            } else {
                if (mPosType == 1) {
                    float centerX = mRectF.left;
                    float centerY = mRectF.top;
                    mDeleteRect.set(centerX - BUTTON_WIDTH, centerY - BUTTON_WIDTH, centerX + BUTTON_WIDTH, centerY + BUTTON_WIDTH);

                    centerX = mRectF.left;
                    centerY = mRectF.bottom;
                    mScaleRect.set(centerX - BUTTON_WIDTH, centerY - BUTTON_WIDTH, centerX + BUTTON_WIDTH, centerY + BUTTON_WIDTH);

                } else if (mPosType == 2) {
                    float centerX = mRectF.right;
                    float centerY = mRectF.top;
                    mDeleteRect.set(centerX - BUTTON_WIDTH, centerY - BUTTON_WIDTH, centerX + BUTTON_WIDTH, centerY + BUTTON_WIDTH);

                    centerX = mRectF.right;
                    centerY = mRectF.bottom;
                    mScaleRect.set(centerX - BUTTON_WIDTH, centerY - BUTTON_WIDTH, centerX + BUTTON_WIDTH, centerY + BUTTON_WIDTH);

                }
            }
        }

        public void onDraw(Canvas canvas) {
            if (mShow) {
                if (mType == TYPE_BREAST) {
                    canvas.drawCircle(mCenterX, mCenterY, mRadius, mCirclePaint);
                    if (mDrawAddIcon) {
                        mDrawableAdd.setBounds((int) mDeleteRect.left, (int) mDeleteRect.top, (int) mDeleteRect.right, (int) mDeleteRect.bottom);
                        mDrawableAdd.draw(canvas);
                    } else {
                        mDrawableDelete.setBounds((int) mDeleteRect.left, (int) mDeleteRect.top, (int) mDeleteRect.right, (int) mDeleteRect.bottom);
                        mDrawableDelete.draw(canvas);
                    }
                    mDrawableScale.setBounds((int) mScaleRect.left, (int) mScaleRect.top, (int) mScaleRect.right, (int) mScaleRect.bottom);
                    mDrawableScale.draw(canvas);
                } else {
                    int save = canvas.save();
                    canvas.rotate(mDegree, mRectF.centerX(), mRectF.centerY());
                    canvas.drawRect(mRectF, mCirclePaint);
                    mDrawableContent.setBounds((int) mRectF.left, (int) mRectF.top, (int) mRectF.right, (int) mRectF.bottom);
                    mDrawableContent.draw(canvas);
                    if (mDrawAddIcon) {
                        mDrawableAdd.setBounds((int) mDeleteRect.left, (int) mDeleteRect.top, (int) mDeleteRect.right, (int) mDeleteRect.bottom);
                        mDrawableAdd.draw(canvas);
                    } else {
                        mDrawableDelete.setBounds((int) mDeleteRect.left, (int) mDeleteRect.top, (int) mDeleteRect.right, (int) mDeleteRect.bottom);
                        mDrawableDelete.draw(canvas);
                    }
                    mDrawableScale.setBounds((int) mScaleRect.left, (int) mScaleRect.top, (int) mScaleRect.right, (int) mScaleRect.bottom);
                    mDrawableScale.draw(canvas);
                    canvas.restoreToCount(save);
                }
            }
        }

        public void setDegree(float degree) {
            //丰胸不支持旋转
            if (mType == TYPE_BUTTOCKS) {
                mDegree += degree;
                if (mDegree > 90) {
                    mDegree = 90;
                } else if (mDegree < -90) {
                    mDegree = -90;
                }
            }
        }

        public void setScale(float scale) {
            Matrix m = new Matrix();
            m.setScale(scale, scale, mRectF.centerX(), mRectF.centerY());
            RectF rect = new RectF();
            m.mapRect(rect, mRectF);
            if (rect.width() / mAttacher.getScale() >= SMALLEST_SIZE && rect.width() / mAttacher.getScale() <= MAX_SIZE) {
                mRectF = rect;
                mCenterX = mRectF.centerX();
                mCenterY = mRectF.centerY();
                mRadius = mRectF.height() / 2;
                updateOtherRect();
            }
        }

        public void move(float dx, float dy) {
            mRectF.offset(dx, dy);
            mCenterX = mRectF.centerX();
            mCenterY = mRectF.centerY();
            mRadius = mRectF.height() / 2;
            updateOtherRect();
        }

        public void dealScaleAndRotation(float downX, float downY, float nowX, float nowY) {
            float px = mRectF.centerX();
            float py = mRectF.centerY();

            float x1 = downX - px;
            float y1 = downY - py;

            float x2 = nowX - px;
            float y2 = nowY - py;

            float scale = (float) (Math.sqrt(x2 * x2 + y2 * y2) / Math.sqrt(x1 * x1 + y1 * y1));

            double degree1 = MathUtil.getDegree(px, py, downX, downY, px + 1, py);
            double degree2 = MathUtil.getDegree(px, py, nowX, nowY, px + 1, py);

            int location1 = MathUtil.getLocation(x1, y1);
            int location2 = MathUtil.getLocation(x2, y2);

            if (location2 == 1 || location2 == 2) {
                degree2 = -degree2;
            }

            if (location1 == 1 || location1 == 2) {
                degree1 = -degree1;
            }

            double degree = degree2 - degree1;

            setScale(scale);
            setDegree((float) degree);
        }

        public void doScaleMove(RectF baseRect, RectF supperRect, Matrix matrix, Matrix cacheMatrix, RectF viewRect) {
            if (mLastMatrix == null) {
                RectF dstRect = new RectF();
                RectF a = new RectF(mRectF);
                a.offset(-viewRect.left, -viewRect.top);

                //防止坐标对他的影响
                RectF supperRect1 = new RectF(supperRect);
                supperRect1.offset(-viewRect.left, -viewRect.top);
                //aScale是 baseRect -> supperRect的缩放值
                float bScale = supperRect1.width() / baseRect.width();
                Matrix m = new Matrix();
                m.postScale(bScale, bScale, baseRect.centerX(), baseRect.centerY());
                m.postTranslate(supperRect1.centerX() - baseRect.centerX(), supperRect1.centerY() - baseRect.centerY());
                m.invert(m);

                //matrixA是去掉 从baseRect转换到supperRect后的Matrix
                Matrix matrixA = new Matrix(matrix);
                matrixA.preConcat(m);
                matrixA.mapRect(dstRect, a);

                float scale = dstRect.width() / a.width();
                float dx = dstRect.centerX() - a.centerX();
                float dy = dstRect.centerY() - a.centerY();

                cacheMatrix.reset();
                cacheMatrix.setScale(scale, scale, a.centerX(), a.centerY());
                cacheMatrix.mapRect(dstRect, a);

                dstRect.offset(viewRect.left, viewRect.top);
                dstRect.offset(dx, dy);

                if (dstRect.width() / mAttacher.getScale() >= SMALLEST_SIZE && dstRect.width() / mAttacher.getScale() <= MAX_SIZE) {
                    mRectF = dstRect;
                    mCenterX = mRectF.centerX();
                    mCenterY = mRectF.centerY();
                    mRadius = mRectF.height() / 2;
                    updateOtherRect();
                }

                mLastMatrix = new Matrix();
                mLastMatrix.set(matrix);
            } else {
                RectF dstRect = new RectF();
                RectF a = new RectF(mRectF);
                a.offset(-viewRect.left, -viewRect.top);

                mLastMatrix.invert(mLastMatrix);
                //matrixA是去掉 从baseRect转换到supperRect后的Matrix
                Matrix matrixA = new Matrix(matrix);
                matrixA.preConcat(mLastMatrix);
                matrixA.mapRect(dstRect, a);

                float scale = dstRect.width() / a.width();
                float dx = dstRect.centerX() - a.centerX();
                float dy = dstRect.centerY() - a.centerY();

                cacheMatrix.reset();
                cacheMatrix.setScale(scale, scale, a.centerX(), a.centerY());
                cacheMatrix.mapRect(dstRect, a);

                dstRect.offset(viewRect.left, viewRect.top);
                dstRect.offset(dx, dy);

                if (dstRect.width() / mAttacher.getScale() >= SMALLEST_SIZE && dstRect.width() / mAttacher.getScale() <= MAX_SIZE) {
                    mRectF = dstRect;
                    mCenterX = mRectF.centerX();
                    mCenterY = mRectF.centerY();
                    mRadius = mRectF.height() / 2;
                    updateOtherRect();
                }
                mLastMatrix.set(matrix);
            }
        }

        private Matrix mLastMatrix;

        public void setLastMatrix(Matrix matrix) {
            if (mLastMatrix == null) {
                mLastMatrix = new Matrix();
            }
            mLastMatrix.set(matrix);
        }

        public Matrix getRotateMatrix() {
            mMatrix.setRotate(-mDegree, mRectF.centerX(), mRectF.centerY());
            return mMatrix;
        }

        public void setDrawAddIcon(boolean drawAddIcon) {
            mDrawAddIcon = drawAddIcon;
        }

        public boolean isDrawAddIcon() {
            return mDrawAddIcon;
        }

        public void reset(float centerX, float centerY, float radius) {
            mCenterX = centerX;
            mCenterY = centerY;
            mRadius = radius;
            mRectF = new RectF(mCenterX - mRadius, mCenterY - mRadius, mCenterX + mRadius, mCenterY + mRadius);

            mDrawAddIcon = false;
            mDegree = 0;
            mShow = true;

            updateOtherRect();
        }

        public void reset(float centerX, float centerY) {
            mCenterX = centerX;
            mCenterY = centerY;
            mRadius = BUTTOCKS_HEIGHT;
            mRectF = new RectF(mCenterX - BUTTOCKS_WIDTH, mCenterY - BUTTOCKS_HEIGHT, mCenterX + BUTTOCKS_WIDTH, mCenterY + BUTTOCKS_HEIGHT);

            mDrawAddIcon = false;
            mDegree = 0;
            mShow = true;

            updateOtherRect();
        }

        public RectF getRectF() {
            return mRectF;
        }

        public float getDegree() {
            return mDegree;
        }

        public RectF getDeleteRect() {
            if (mRectF.width() < DEFAULT_RADIUS) {
                return mDeleteRect;
            }
            float centerX = mDeleteRect.centerX();
            float centerY = mDeleteRect.centerY();
            mButtonRect.set(centerX - BUTTON_TOUCH_WIDTH, centerY - BUTTON_TOUCH_WIDTH, centerX + BUTTON_TOUCH_WIDTH, centerY + BUTTON_TOUCH_WIDTH);
            return mButtonRect;
        }

        public RectF getScaleRect() {
            if (mRectF.width() < DEFAULT_RADIUS) {
                return mScaleRect;
            }
            float centerX = mScaleRect.centerX();
            float centerY = mScaleRect.centerY();
            mButtonRect.set(centerX - BUTTON_TOUCH_WIDTH, centerY - BUTTON_TOUCH_WIDTH, centerX + BUTTON_TOUCH_WIDTH, centerY + BUTTON_TOUCH_WIDTH);
            return mButtonRect;
        }

        public boolean isShow() {
            return mShow;
        }

        public void setShow(boolean show) {
            mShow = show;
        }
    }
}
